package org.timemachine.query;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.persistence.Query;

import org.timemachine.query.util.QueryConstants;

public class test implements QueryConstants{

	public static void main(String[] args) {
		
		// oncelikle sql'in syntax'inin dogru oldugunu sql'i run ederek test etmekte fayda var.
		// createQuery vb bu isi yapar, exception throw eder, baska sekilde bize query gelir mi ? buna izin vermemek lazim....
		
//		String baseSql = "select u from Unit as u where dsadad dsadasda  dsdasdas order by id desc";
//		String baseSql2 = "select u from Unit as u order by id desc";
		
		String baseSql3 = "select e from Employee as e ";
		
		String res = "select e from EmployeeChange e  join " +
					" e.beginChangeInfo begin join e.endChangeInfo cend " +
					" where begin.changeTimeStamp < :cdate and cend.changeTimeStamp > :cdate ";
		
		
		String baseSql = "select e from Employee e join e.unit u order by desc";
		
		String res2 = "select e from EmployeeChange e join e.unitChange u" +
				" join e.beginChangeInfo begin join e.endChangeInfo cend " +
				" join u.beginChangeInfo begin2 join u.endChangeInfo cend2 " +
				" where begin.changeTimeStamp< :cdate and cend.changeTimeStamp> :cdate and " +
				" begin2.changeTimeStamp< :cdate and cend2.changeTimeStamp> :cdate" +
				" and .....";
		
		try {
			System.err.println(TimeMachineQuery.generateQuery(baseSql));
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
//		
//		// exception yazmayi unutma....
//
//		// Query resQuery = TimeMachineQuery.createTimeMachineQuery(baseSql,em,new Date());
//		
//		String selectWithFrom = getSelectFromStatement(baseSql);
//		
//		String queryAfterFrom = getQueryAfterFrom(baseSql);
//		
//		String whereStatement = getWhereStatment(baseSql);
//		
//		String queryBetweenFromAndWhere = getQueryBetweenFromAndWhere(queryAfterFrom);
//		
//		String fromClauseCommandsRemoved = discardFromClauseCommands(queryBetweenFromAndWhere);
//		
//		String joinStatementType = getJoinStatementType(queryBetweenFromAndWhere);
//		String joinClauseCommandsRemoved = discardJoinClauseCommands(fromClauseCommandsRemoved);
//		
//		Map<String, String> tableAliasPairs = getTableNamesAndAlias(joinClauseCommandsRemoved);
//		
//		String joinStatement=getJoinStatement(fromClauseCommandsRemoved);
//		
//		Map<String, String> objectJoinPair =  parseJoinStatement(tableAliasPairs, joinStatement);
//		
//		Map<String, String> tableAliasPairWithChange = prepareTableNames(tableAliasPairs);
//		Map<String, String> joinTableAliasPairWithChange = prepareTableNames(objectJoinPair);
//		
//		List<String> generatedStatementList = prepareFromStatement(tableAliasPairWithChange);
//		
//		String alias = "";
//		
//		for (Map.Entry<String, String> entry : tableAliasPairs.entrySet()) {
//			alias = entry.getValue();
//		}
//		
//		
//		List<String> generatedJoinStatementList = prepareFromStatementForJoin(joinTableAliasPairWithChange,alias,joinStatementType);
//		
//		// concentrate statements for resultTimeMachineQuery
//
//		StringBuffer resBuffer = new StringBuffer();
//		
//		resBuffer.append(selectWithFrom);
//		resBuffer.append(generatedStatementList.get(0));
//		resBuffer.append(generatedJoinStatementList.get(0));
//		
//		resBuffer.append(" where ");
//		resBuffer.append(generatedStatementList.get(1));
//		resBuffer.append(generatedJoinStatementList.get(1));
//		
//		if(whereStatement != null & !"".equals(whereStatement)){
//			resBuffer.append(" and ");
//			resBuffer.append(whereStatement);
//		}
//		else{
//			resBuffer.append(" ");
//			resBuffer.append(baseSql.substring((baseSql.indexOf(fromClauseCommandsRemoved))+fromClauseCommandsRemoved.length(), baseSql.length()));
//		}
//		
//		System.err.println("*******************RESULT****************");
//		System.err.println(resBuffer.toString());
//		System.err.println("***********************************");
		
	}
	
	private static String getJoinStatement(String sql){
		
		if(sql !=null && !"".equals(sql) && sql.toUpperCase().contains(JOIN)){
			
			for (String _command : new ArrayList<String>(Arrays.asList(joinClauseCommands))) {
				
				if(sql.toUpperCase().contains(_command)){
					sql = sql.substring(sql.toUpperCase().indexOf(_command)+_command.length(),sql.length());
				}
			}
			
			if(sql.toUpperCase().contains(JOIN)){
				sql = sql.substring(sql.toUpperCase().indexOf(JOIN)+JOIN.length(),sql.length());
			}
			
			return sql;
		}
		else{
			return "";
		}
		
	}
	
	public static String discardJoinClauseCommands(String sql){
		
		if(sql !=null && !"".equals(sql)){
			
			for (String _command : new ArrayList<String>(Arrays.asList(joinClauseCommands))) {
				
				if(sql.toUpperCase().contains(_command)){
					sql = sql.substring(0, sql.toUpperCase().indexOf(_command));
				}
			}
			
			if(sql.toUpperCase().contains(JOIN)){
				sql = sql.substring(0,sql.toUpperCase().indexOf(JOIN));
			}
			
			return sql;
		}
		else{
			return sql;
		}
		
	}
	
	private static Map<String, String> parseJoinStatement(Map<String, String> tableAliasPairs, String joinStatement){
		
		Map<String, String> objectJoinPair = new HashMap<String,String>();
		String resStatement = joinStatement;
		Iterator it = tableAliasPairs.entrySet().iterator();

		while (it.hasNext()) {
			
			Map.Entry mapEntry = (Map.Entry) it.next();
			
			if(resStatement.toUpperCase().contains(AS_ALLIAS)){
				resStatement = resStatement.replace(AS_ALLIAS, "");
				resStatement = resStatement.replace(AS_ALLIAS_LOWER, "");
			}
			
			resStatement = resStatement.trim();
			
			String [] res = resStatement.substring(resStatement.indexOf(mapEntry.getValue()+"."), resStatement.length()).split(" ");
			objectJoinPair.put((Arrays.asList(res).get(0).substring(Arrays.asList(res).get(0).indexOf(".")+1,Arrays.asList(res).get(0).length())).trim(), 
					Arrays.asList(res).get(1).trim());
			continue;
		}

		return objectJoinPair;
	}
	
	
	private static String getSelectFromStatement(String sql) {
		
		if( sql!=null && sql.toUpperCase().contains(FROM_CLAUSE)) {
			return (sql.substring(0, sql.toUpperCase().indexOf(FROM_CLAUSE)).trim())+" from ";
		}
		else{
			return "";
		}
		
		
	}

	public static String getQueryAfterFrom(String sql) {
		
		if( sql!=null && sql.toUpperCase().contains(FROM_CLAUSE)) {
			return sql.substring(sql.toUpperCase().indexOf(FROM_CLAUSE)+FROM_CLAUSE.length(),sql.length()).trim();
		}
		else{
			return "";
		}

	}
	
	public static String getWhereStatment(String sql) {
		
		String statement = getQueryAfterFrom(sql);
		
		if( statement!=null && statement.toUpperCase().contains(WHERE_CLAUSE)) {
			return statement.substring(statement.toUpperCase().indexOf(WHERE_CLAUSE)+WHERE_CLAUSE.length(),statement.length()).trim();
		}
		else{
			return "";
		}

	}
	
	public static String getQueryBetweenFromAndWhere(String sql) {
		
		if( sql!=null && sql.toUpperCase().contains(WHERE_CLAUSE)) {
			return sql.substring(0,sql.toUpperCase().indexOf(WHERE_CLAUSE));
		}
		else{
			return sql;
		}

	}
	
	public static String discardFromClauseCommands(String sql){
		
		if(sql !=null && !"".equals(sql)){
			
			for (String _command : new ArrayList<String>(Arrays.asList(fromClauseCommands))) {
				
				if(sql.toUpperCase().contains(_command)){
					sql = sql.substring(0, sql.toUpperCase().indexOf(_command));
				}
			}
			
			return sql;
		}
		else{
			return sql;
		}
		
	}
	
	public static Map<String,String> getTableNamesAndAlias(String sql){
		
		Map<String, String> resultMap = new HashMap<String,String>();
		
		String res = sql;
		
		if(sql.toUpperCase().contains(AS_ALLIAS)){
			res = sql.replace(AS_ALLIAS, "");
			res = sql.replace(AS_ALLIAS_LOWER, "");
		}
		
		String [] tableAndAliasPair = (res.trim()).split(" +"); 
		
		if(tableAndAliasPair != null && tableAndAliasPair.length>1){
			resultMap.put(tableAndAliasPair[0].trim(), tableAndAliasPair[1].trim());
		}
			
		
		return resultMap;
		
	}
	
	public static Map<String, String> prepareTableNames(Map<String, String> tableAliasPairs){
		
		Map<String, String> tableAliasParesWithChange = new HashMap<String, String>();
		
		Iterator it = tableAliasPairs.entrySet().iterator();
		
		while (it.hasNext()) {
			Map.Entry mapEntry = (Map.Entry) it.next();
			tableAliasParesWithChange.put(mapEntry.getKey()+"Change", (String) mapEntry.getValue());
			continue;
		}
		
		return tableAliasParesWithChange;
	}
	
	public static ArrayList<String> prepareFromStatementForJoin(Map<String, String> joinTableAliasPairWithChange,
			String fromObjectAlias,String joinStatementType){
		
		ArrayList<String> resultList = new ArrayList<String>();

		StringBuffer buffer = new StringBuffer();
		StringBuffer buffer2 = new StringBuffer();

		Iterator it = joinTableAliasPairWithChange.entrySet().iterator();
		while (it.hasNext()) {

			Map.Entry mapEntry = (Map.Entry) it.next();
			buffer.append(" "+joinStatementType);
			buffer.append(fromObjectAlias);
			buffer.append(".");
			buffer.append(mapEntry.getKey());
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(" ");
			buffer.append("join");
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(".beginChangeInfo ");
			buffer.append("begin2");
			buffer.append(" ");
			buffer.append("join");
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(".endChangeInfo ");
			buffer.append("cend2");

			buffer2.append(" and ");
			buffer2.append("begin2");
			buffer2.append(".changeTimeStamp < ");
			buffer2.append(":cdate");
			buffer2.append(" and ");
			buffer2.append("cend2");
			buffer2.append(".changeTimeStamp > ");
			buffer2.append(":cdate");

		}

		resultList.add(buffer.toString());
		resultList.add(buffer2.toString());

		return resultList;
		
	}
	
	public static ArrayList<String> prepareFromStatement(Map<String, String> tableAliasPairWithChange){
		
		ArrayList<String> resultList = new ArrayList<String>();
		
		StringBuffer buffer = new StringBuffer();
		StringBuffer buffer2 = new StringBuffer();
		
		Iterator it = tableAliasPairWithChange.entrySet().iterator();
		while (it.hasNext()) {
			
			Map.Entry mapEntry = (Map.Entry) it.next();
			
			buffer.append(mapEntry.getKey());
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(" ");
			buffer.append("join");
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(".beginChangeInfo ");
			buffer.append("begin");
			buffer.append(" ");
			buffer.append("join");
			buffer.append(" ");
			buffer.append(mapEntry.getValue());
			buffer.append(".endChangeInfo ");
			buffer.append("cend");
			buffer.append(" ");
			
			buffer2.append("begin");
			buffer2.append(".changeTimeStamp < ");
			buffer2.append(":cdate");
			buffer2.append(" and ");
			buffer2.append("cend");
			buffer2.append(".changeTimeStamp > ");
			buffer2.append(":cdate");
			
			
		}
		
		resultList.add(buffer.toString());
		resultList.add(buffer2.toString());
		
		return resultList;
		
	}
	
	public static String getJoinStatementType(String sql){
	
		if(sql !=null && !"".equals(sql)){
			
			for (String _command : new ArrayList<String>(Arrays.asList(joinClauseCommands))) {
				
				if(sql.toUpperCase().contains(_command)){
					return _command; 
				}
			}
			
			if(sql.toUpperCase().contains(JOIN)){
				return JOIN;
			}
			else{
				return "";
			}
		}
		else{
			return "";
		}
		
	}
	
	
}
